`timescale 1ns / 1ps 
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2022/02/26 15:17:50
// Design Name:
// Module Name: ps2_kb_rx
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////


module ps2_kb_rx(
           clk,
           resetb,
           rxc,
           rxd,
           oe,
           odat

       );
input clk;
input resetb;
input rxc;
input rxd;
output oe;
output [7: 0] odat;
parameter ck2q = 1;
reg rxc_d0, rxc_d1, rxc_d2;
wire rxc_ne = ~rxc_d1 & rxc_d2;
wire rxc_pe = ~rxc_d2 & rxc_d1;
always@(posedge clk or negedge resetb)
	begin
		if (!resetb)
			begin
				rxc_d0 <= #ck2q 0;
				rxc_d1 <= #ck2q 0;
				rxc_d2 <= #ck2q 0;
			end
		else
			begin
				rxc_d0 <= #ck2q rxc;
				rxc_d1 <= #ck2q rxc_d0;
				rxc_d2 <= #ck2q rxc_d1;
			end
	end
reg rxd_d0, rxd_d1, rxd_d2;
wire rxd_ne = ~rxd_d1 & rxd_d2;

always@(posedge clk or negedge resetb)
	begin
		if (!resetb)
			begin
				rxd_d0 <= #ck2q 0;
				rxd_d1 <= #ck2q 0;
				rxd_d2 <= #ck2q 0;
			end
		else
			begin
				rxd_d0 <= #ck2q rxd;
				rxd_d1 <= #ck2q rxd_d0;
				rxd_d2 <= #ck2q rxd_d1;
			end
	end

//state operation
localparam IDLE = 3'd0;
localparam START = 3'd1;
localparam DATA = 3'd2;
localparam PARITY = 3'd3;
localparam STOP = 3'd4;
localparam SEND = 3'd5;

reg [2: 0] state;
reg [2: 0] dat_cnt;
reg [7: 0] odat_r;
reg parity_bit;

always@(posedge clk or negedge resetb)
	begin
		if (!resetb)
			begin
				state <= #ck2q IDLE;
				dat_cnt <= #ck2q 0;
				odat_r <= #ck2q 0;
				parity_bit <= #ck2q 0;
			end
		else
			case (state)
				IDLE:
					begin
						odat_r <= #ck2q 0;
						parity_bit <= #ck2q 0;
						if (rxd_ne & rxc_d2)
							state <= #ck2q START;
					end
				START:
					if (rxc_ne)
						state <= #ck2q DATA;
				DATA:
					if (rxc_ne)
						begin
							parity_bit <= #ck2q parity_bit ^ rxd_d2;
							odat_r[dat_cnt] <= #ck2q rxd_d2;
							dat_cnt <= #ck2q dat_cnt + 1'b1;
							if (dat_cnt == 7)
								state <= #ck2q PARITY;
						end
				PARITY:
					//odd
					if (rxc_ne)
						begin
							parity_bit <= #ck2q parity_bit ^ rxd_d2;
							state <= #ck2q STOP;
						end
				STOP:
					if (rxc_pe & parity_bit)
						state <= #ck2q SEND;
				SEND:
					begin
						state <= #ck2q IDLE;
					end
			endcase
	end

wire oe_w = (state == SEND);
reg oe;
always@(posedge clk or negedge resetb)
	begin
		if (!resetb)
			oe <= #ck2q 0;
		else
			oe <= #ck2q oe_w;
	end

reg [7: 0] odat;
always@(posedge clk or negedge resetb)
	begin
		if (!resetb)
			odat <= #ck2q 0;
		else if (oe_w)
			odat <= #ck2q odat_r;
	end

endmodule
